<template>
  <div class="wrap">
    <div class="header">
      <span>流程图 Demo</span>
    </div>
    <div class="content">
      <div id="stencil" class="sider"/>
      <div class="panel">
        <div class="toolbar">
          <el-tooltip content="删除 ctrl + D" placement="bottom" effect="light">
            <el-button icon="el-icon-close" circle @click="handleClick('delete')"></el-button>
          </el-tooltip>
          <el-tooltip content="撤回 ctrl + z" placement="bottom" effect="light">
            <el-button icon="el-icon-arrow-left" circle @click="handleClick('undo')"></el-button>
          </el-tooltip>
          <el-tooltip content="回退 ctrl + shift + z" placement="bottom" effect="light">
            <el-button icon="el-icon-arrow-right" circle @click="handleClick('redo')"></el-button>
          </el-tooltip>
          <el-tooltip content="拷贝 ctrl + c" placement="bottom" effect="light">
            <el-button icon="el-icon-plus" circle @click="handleClick('copy')"></el-button>
          </el-tooltip>
          <el-tooltip content="剪切 ctrl + x" placement="bottom" effect="light">
            <el-button icon="el-icon-news" circle @click="handleClick('cut')"></el-button>
          </el-tooltip>
          <el-tooltip content="past ctrl + v" placement="bottom" effect="light">
            <el-button icon="el-icon-news" circle @click="handleClick('paste')"></el-button>
          </el-tooltip>
          <el-tooltip content="保存 ctrl + s" placement="bottom" effect="light">
            <el-button icon="el-icon-news" circle @click="handleClick('save')"></el-button>
          </el-tooltip>
          <el-tooltip content="打印 ctrl + p" placement="bottom" effect="light">
            <el-button icon="el-icon-printer" circle @click="handleClick('print')"></el-button>
          </el-tooltip>
          <el-tooltip content="新增循环节点" placement="bottom" effect="light">
            <el-button  @click="addForShape('22')">新增循环节点</el-button>
          </el-tooltip>
        </div>
        <div id="container" class="x6-graph"/>
      </div>
    </div>

    <!-- 弹窗, 新增 / 修改 -->
    <node v-if="addOrUpdateVisible" ref="addOrUpdate" @createForShape="createForShape"></node>

  </div>
</template>

<script>
  import {Graph, Addon, FunctionExt, Shape} from '@antv/x6'
  import {
    FlowChartRect,
    FlowChartImageRect,
    FlowChartTitleRect,
    FlowChartAnimateText,
    NodeGroup
  } from './shape'
  import {DataUri} from '@antv/x6'
  import graphData from './data'
  //import { getInfo, updateFlow } from '@/api/scene'
  import { pageList } from '@/api/baseConfig/entity'
  import Node from './node'

export default {
    data () {
      return {
        graph: {},
        history: {},
        canUndo: false,
        canRedo: false,
        id: '',
        ruleList: [],
        stencilShapeList: [],
        sceneInfo: [],
        addOrUpdateVisible: false
      }
    },
    components: {
      Node
    },
    mounted () {
      this.id = this.$route.query.id

      this.graph = this.init()
      const resizeFn = () => {
        const {width, height} = this.getContainerSize()
        this.graph.resize(width, height)
      }
      resizeFn()

      window.addEventListener('resize', resizeFn)
      return () => {
        window.removeEventListener('resize', resizeFn)
      }
      this.history = this.graph
      this.setCanUndo(this.history.canUndo())
      this.setCanRedo(this.history.canRedo())
      this.history.on('change', () => {
        this.setCanUndo(this.history.canUndo())
        this.setCanRedo(this.history.canRedo())
      })
      this.graph.bindKey('ctrl+z', () => {
        if (this.history.canUndo()) {
          this.history.undo()
        }
        return false
      })
      this.graph.bindKey('ctrl+shift+z', () => {
        if (this.history.canRedo()) {
          this.history.redo()
        }
        return false
      })
      this.graph.bindKey('ctrl+d', () => {
        this.graph.clearCells()
        return false
      })
      this.graph.bindKey('ctrl+s', () => {
        // this.graph.toPNG((datauri) => {
        //   DataUri.downloadDataUri(datauri, 'chart.png')
        // })
        this.save()
        return false
      })
      this.graph.bindKey('ctrl+p', () => {
        this.graph.printPreview()
        return false
      })
      this.graph.bindKey('ctrl+c', copy)
      this.graph.bindKey('ctrl+v', paste)
      this.graph.bindKey('ctrl+x', cut)
    },
    methods: {

      init () {
        this.graph = new Graph({
          container: document.getElementById('container'),
          width: 0,
          height: 0,
          grid: {
            size: 10,
            visible: true,
            type: 'doubleMesh',
            args:
  [
    {
      color: '#cccccc',
      thickness: 1
    },
    {
      color: '#5F95FF',
      thickness: 1,
      factor: 4
    }
  ]
          },
          selecting: {
            enabled: true,
            multiple: true,
            rubberband: true,
            movable: true,
            showNodeSelectionBox: true,
            filter: (node) => {
              const data = node.getData()
              return !(data && data.parent)
            }
          },
          connecting: {
            anchor: 'center',
            connectionPoint: 'anchor',
            dangling: false,
            highlight: true,
            snap: true,
            createEdge () {
              return new Shape.Edge({
                attrs: {
                  line: {
                    stroke: '#5F95FF',
                    strokeWidth: 1,
                    targetMarker: {
                      name: 'classic',
                      size: 8
                    }
                  }
                },
                router: {
                  name: 'manhattan'
                }
              })
            },
            validateConnection ({
                                 sourceView,
                                 targetView,
                                 sourceMagnet,
                                 targetMagnet
                               }) {
              if (sourceView === targetView) {
                return false
              }
              if (!sourceMagnet) {
                return false
              }
              if (!targetMagnet) {
                return false
              }
              return true
            }
          },
          highlighting: {
            magnetAvailable: {
              name: 'stroke',
              args: {
                padding: 4,
                attrs: {
                  strokeWidth: 4,
                  stroke: 'rgba(223,234,255)'
                }
              }
            }
          },
          snapline: true,
          history: true,
          clipboard: {
            enabled: true
          },
          keyboard: {
            enabled: true
          },
          embedding: {
            enabled: true,
            findParent ({node}) {
              const bbox = node.getBBox()
              return this.getNodes().filter((node) => {
                // 只有 data.parent 为 true 的节点才是父节点
                const data = node.getData()
                if (data && data.parent) {
                  const targetBBox = node.getBBox()
                  return bbox.isIntersectWithRect(targetBBox)
                }
                return false
              })
            }

          }

        })
        this.initStencil()
        this.initShape()
        this.initEvent()
        return this.graph
      },

      initStencil () {
        this.stencil = new Addon.Stencil({
          target: this.graph,
          stencilGraphWidth: 280,
          search: {rect: true},
          collapsable: true,
          groups: [
            {
              name: 'basic',
              title: '节点',
              graphHeight: 900
            }
          ]
        })
        const stencilContainer = document.querySelector('#stencil')
        stencilContainer.appendChild(this.stencil.container)
      },

      initShape () {
        const r1 = new FlowChartRect({
          attrs: {
            body: {
              rx: 24,
              ry: 24,
              fill: '#2ECC71', // 背景颜色
              stroke: '#000'  // 边框颜色
            },
            text: {
              text: '起始节点'
            }
          }
        })

        const r3 = new FlowChartRect({
          width: 52,
          height: 52,
          angle: 45,
          attrs: {
            'edit-text': {
              style: {
                transform: 'rotate(-45deg)'
              }
            },
            text: {
              text: '判断节点',
              transform: 'rotate(-45deg)'
            }
          },
          ports: {
            groups: {
              top: {
                position: {
                  name: 'top',
                  args: {
                    dx: -26
                  }
                }
              },
              right: {
                position: {
                  name: 'right',
                  args: {
                    dy: -26
                  }
                }
              },
              bottom: {
                position: {
                  name: 'bottom',
                  args: {
                    dx: 26
                  }
                }
              },
              left: {
                position: {
                  name: 'left',
                  args: {
                    dy: 26
                  }
                }
              }
            }
          }
        })
        const r4 = new FlowChartRect({
          width: 70,
          height: 70,
          attrs: {
            body: {
              rx: 35,
              ry: 35
            },
            text: {
              text: '链接节点'
            }
          }
        })
        const r5 = new FlowChartRect({
          attrs: {
            body: {
              rx: 24,
              ry: 24,
              fill: '#2ECC71', // 背景颜色
              stroke: '#000'  // 边框颜色
            },
            text: {
              text: '结束节点'
            }
          }
        })
        const r6 = new FlowChartRect({
          attrs: {
            body: {
              fill: '#CD5C5C', // 背景颜色
              stroke: '#000'  // 边框颜色
            },
            text: {
              text: '循环节点',
              type: 'forNode'
            }
          }
        })
        const c1 = new FlowChartImageRect()
        const c2 = new FlowChartTitleRect()
        const c3 = new FlowChartAnimateText()
        this.stencilShapeList.push(r1)
        this.stencilShapeList.push(r5)
        getInfo({id: this.id + ''}).then(res => {
          this.ruleList = res.data.data.ruleInfos
          this.sceneInfo = res.data.data.info
          if (this.sceneInfo.sceneFlow) {
            this.graph.fromJSON(JSON.parse(this.sceneInfo.sceneFlow))
          }
          this.ruleList.forEach(item => {
            const r2 = new FlowChartRect({
              attrs: {
                body: {
                  fill: '#4F94CD', // 背景颜色
                  stroke: '#000'  // 边框颜色
                },
                text: {
                  text: item.ruleName,
                  ruleId: item.ruleId,
                  type: 'simple'
                }
              }
            })
            this.stencilShapeList.push(r2)
          })
          this.stencil.load(this.stencilShapeList, 'basic')
        })

        this.stencil.load([c1, c2, c3], 'combination')
      },

      showPorts (ports, show) {
        for (let i = 0, len = ports.length; i < len; i = i + 1) {
          ports[i].style.visibility = show ? 'visible' : 'hidden'
        }
      },

      initEvent () {
        const {graph} = this
        const container = document.getElementById('container')
        graph.on('node:contextmenu', ({e, x, y, cell, view}) => {
          cell.attr('text/style/display', 'none')
          const elem = view.container.querySelector('.x6-edit-text')
          if (elem) {
            elem.focus()
          }
        })
        graph.on(
          'node:mouseenter',
          FunctionExt.debounce(() => {
            const ports = container.querySelectorAll('.x6-port-body')
            this.showPorts(ports, true)
          }),
          500
        )
        graph.on('node:mouseleave', () => {
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, false)
        })

        graph.on('node:collapse', ({node}) => {
          node.toggleCollapse()
          const collapsed = node.isCollapsed()
          const cells = node.getDescendants()
          cells.forEach((node) => {
            if (collapsed) {
              node.hide()
            } else {
              node.show()
            }
          })
        })

        graph.bindKey('backspace', () => {
          const cells = graph.getSelectedCells()
          if (cells.length) {
            graph.removeCells(cells)
          }
        })
      },
      getContainerSize () {
        return {
          width: document.body.offsetWidth - 581,
          height: document.body.offsetHeight - 87
        }
      },
      copy () {
        const cells = this.graph.getSelectedCells()
        if (cells.length) {
          this.graph.copy(cells)
        }
        return false
      },
      cut () {
        const cells = this.graph.getSelectedCells()
        if (cells.length) {
          this.graph.cut(cells)
        }
        return false
      },
      paste () {
        if (!this.graph.isClipboardEmpty()) {
          const cells = this.graph.paste({offset: 32})
          this.graph.cleanSelection()
          this.graph.select(cells)
        }
        return false
      },
      save () {
        updateFlow({id: this.id + '', flow: this.graph.toJSON()}).then(res => {
        })
      },
      setCanUndo (value) {
        this.canUndo = value
      },
      setCanRedo (value) {
        this.canRedo = value
      },
      handleClick (name) {
        switch (name) {
          case 'undo':
            this.graph.history.undo()
            break
          case 'redo':
            this.graph.history.redo()
            break
          case 'delete':
            this.graph.clearCells()
            break
          case 'save':
            // console.log(JSON.stringify(this.graph.toJSON()))
            this.save()
          // this.graph.toPNG((datauri) => {
          //   DataUri.downloadDataUri(datauri, 'chart.png')
          // })
            break
          case 'print':
            this.graph.printPreview()
            break
          case 'copy':
            this.copy()
            break
          case 'cut':
            this.cut()
            break
          case 'paste':
            this.paste()
            break
          default:
            break
        }
      },
      // 获取数据列表
      createForShape (name, text) {
        const r6 = new FlowChartRect({
          attrs: {
            body: {
              fill: '#CD5C5C', // 背景颜色
              stroke: '#000'  // 边框颜色
            },
            text: {
              text: text,
              id: name,
              type: 'forNode'
            }
          }
        })
        this.graph.addNode(r6)
      },
      // 新增 / 修改
      addForShape (id) {
        this.addOrUpdateVisible = true
        this.$nextTick(() => {
          this.$refs.addOrUpdate.init(id)
        })
      }
    }
  }
</script>

<style lang="scss">

  html,
  body,
  #root {
    height: 100%;
  }

  body {
    margin: 0;
  }

  .x6-widget-snapline-vertical {
    border-right-color: #ff4e50 !important;
  }

  .x6-widget-snapline-horizontal {
    border-bottom-color: #ff4e50 !important;
  }

  .x6-widget-selection-box {
    border: 1px dashed #5f95ff;
  }

  .x6-widget-selection-inner {
    border: 1px dashed #5f95ff;
  }

  .x6-widget-stencil-content {
    height: 1000px;
  }

  @keyframes stroke {
    100% {
      stroke-dashoffset: -400;
    }
  }

  .animate-text1,
  .animate-text2,
  .animate-text3,
  .animate-text4 {
    font-weight: bold;
    fill: none;
    stroke-width: 2px;
    stroke-dasharray: 90 310;
    animation: stroke 3s infinite linear;
  }

  .animate-text1 {
    stroke: #873bf4;
    text-shadow: 0 0 2px #873bf4;
    animation-delay: -1.5s;
  }

  .animate-text2 {
    stroke: #ff6e06;
    text-shadow: 0 0 2px #ff6e06;
    animation-delay: -3s;
  }

  .wrap {
    width: 100%;
    height: 100%;

    .header {
      display: flex;
      justify-content: space-between;
      height: 48px;
      line-height: 48px;
      padding-left: 16px;
      padding-right: 32px;
      background: #fff;
      box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
      position: relative;
      color: rgba(0, 0, 0, 0.45);
    }

    .content {
      display: flex;
      height: calc(100% - 48px);

      .sider {
        position: relative;
        width: 290px;
        height: 100%;
        border-right: 1px solid rgba(0, 0, 0, 0.08);
      }

      .panel {
        height: 100%;

        .toolbar {
          display: flex;
          align-items: center;
          height: 38px;
          background-color: #f7f9fb;
          border-bottom: 1px solid rgba(0, 0, 0, 0.08);
        }
      }

      .config {
        box-sizing: border-box;
        width: 290px;
        height: 100%;
        padding: 0 24px;
        border-left: 1px solid rgba(0, 0, 0, 0.08);
      }
    }
  }


</style>
